using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.XPath;  
using Rest.Service;
using Rest.Xml;
using Rest.Transport;  

namespace Rest.Service.Samples
{
    /// <summary>
    /// Represents service for fetching geocoding information from Yahoo.
    /// See: http://developer.yahoo.com/maps/rest/V1/geocode.html
    /// </summary>
    /// <remarks>
    /// Service responds with something like:
    /// <code>
    ///     <ResultSet 
    ///         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    ///         xmlns="urn:yahoo:maps" 
    ///         xsi:schemaLocation="urn:yahoo:maps http://api.local.yahoo.com/MapsService/V1/GeocodeResponse.xsd">
    ///         <Result precision="address">
    ///             <Latitude>37.416405</Latitude>
    ///             <Longitude>-122.024933</Longitude>
    ///             <Address>703 FIRST AVE</Address>
    ///             <City>SUNNYVALE</City>
    ///             <State>CA</State>
    ///             <Zip>94089-1019</Zip>
    ///             <Country>US</Country>
    ///         </Result>
    ///     </ResultSet>
    ///     <!-- ws02.search.scd.yahoo.com uncompressed/chunked Thu Oct 26 02:47:07 PDT 2006 -->
    /// </code>
    /// </remarks>
    public class YahooGeocodingService : RestServiceProxyBase 
    {
        /// <summary>
        /// See: http://developer.yahoo.com/maps/rest/V1/geocode.html
        /// </summary>
        public const String YahooGeocodeAppId = "YahooDemo";

        /// <summary>
        /// Geocodes an address (US only)
        /// </summary>
        /// <param name="street"></param>
        /// <param name="city"></param>
        /// <param name="state"></param>
        /// <returns>
        /// String representation of the address
        /// </returns>
        /// <example>
        ///     <code>
        ///         YahooGeocodingService yahooGeocodeService = new YahooGeocodingService();
        ///         String geocodedAddress = yahooGeocodeService.GeocodeAddress(
        ///             "703 First Street", "Sunnyvale", "CA");
        ///     </code>
        /// </example>
        public String GeocodeAddress(String street, String city, String state) 
        {
            RestCommand restCommand = new RestCommand(
                "http://api.local.yahoo.com/MapsService/V1/geocode");

            restCommand.Transport = new GetRestTransport();
            restCommand.Parameters.Add("appid", YahooGeocodeAppId);
            restCommand.Parameters.Add("street", street);
            restCommand.Parameters.Add("city", city);
            restCommand.Parameters.Add("state", state);   
            
            XmlDocument xml = null;

            try
            {
                xml = base.Invoke(restCommand); 
            }
            catch (RestServiceException)
            {
                //
                // An exception has been thrown by the service internally. We are being notified.
                //
            }
            catch (RestException ex)
            {
                // An exception has been thrown in our own classes
                return ex.Message;
            }

            XmlNamespaceManager namespaceManager = 
                new XmlNamespaceManager(xml.NameTable);

            // TODO: BJB, default namespace is giving problems for some reason
            namespaceManager.AddNamespace("map",
                "urn:yahoo:maps");

            String latitude = xml.SelectSingleNode(
                "//map:ResultSet/map:Result/map:Latitude", 
                namespaceManager).InnerText;

            String longitude = xml.DocumentElement.SelectSingleNode(
                "//map:ResultSet/map:Result/map:Longitude",
                namespaceManager).InnerText;

            String googleMapsLink = String.Format(
                "http://maps.google.com/?ie=UTF8&z=5&ll={0},{1}&spn=19.667318,41.220703", 
                latitude, longitude);

            return String.Format("lat: {0}, long: {1}\r\n\r\n{2}", 
                latitude, longitude, googleMapsLink);
        }
    }
}
